package client;

import entity.Client;
import server.GpcRequest;
import server.GpcRequestHandler;
import tool.ExecutorServiceTool;
import tool.StreamUtils;
import tool.StringUtils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * 客户端
 * @author lijiahao
 */
public class BaseClient extends Client {

	private static final long serialVersionUID = 7414695742934174697L;
	// 空闲计数器,如果空闲超过10次,将检测server是否中断连接.
	//存储SelectionKey的队列
	//private static BlockingQueue<GpcRequest> requests = new LinkedBlockingQueue<GpcRequest>();
	private SocketChannel socketChannel = null;
	private Selector selector= null;
	public String id = "-1";

	public BaseClient() {
		setObjType("connect");
		Runtime.getRuntime().addShutdownHook(new Thread(new ShutDownThread()));
	}

	class ShutDownThread implements Runnable {

		@Override
		public void run() {
			try {
				System.out.println("正在关闭程序");
				sendFirstMsg();
				TimeUnit.SECONDS.sleep(2);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}//模拟应用进程退出前的处理操作
		}

	}
	
	public void init(SocketChannel socketChannel) throws IOException {
		this.ip = StringUtils.splitGet(socketChannel.getLocalAddress().toString().replaceFirst("/", ""),":",0);
		this.targetIp = StringUtils.splitGet(socketChannel.getRemoteAddress().toString().replaceFirst("/", ""),":",0);
		this.port = StringUtils.splitGet(socketChannel.getLocalAddress().toString().replaceFirst("/", ""),":",1);
		this.targetPort = StringUtils.splitGet(socketChannel.getRemoteAddress().toString().replaceFirst("/", ""),":",1);
	}

	public void conn(String serverName, int port) throws UnknownHostException, IOException, InterruptedException {
		selector = Selector.open();
		socketChannel = SocketChannel.open();
		//1.连接服务器
		boolean isConnected = socketChannel.connect(new InetSocketAddress(serverName,port));
		//2.初始化连接信息
		init(socketChannel);
		//2.将通道设置为非阻塞方式
		socketChannel.configureBlocking(false);
		//3.初始化一个消息发送
		SelectionKey key = socketChannel.register(selector, SelectionKey.OP_READ);

		if (isConnected) {
			this.sendFirstMsg();
			ExecutorServiceTool.execute(() -> {
				try {
					ReadAndWriteStart();
				} catch (IOException e) {
					e.printStackTrace();
				}
			});
		} else {
			// 如果连接还在尝试中,则注册connect事件的监听. connect成功以后会出发connect事件.
			key.interestOps(SelectionKey.OP_CONNECT);
		}
	}

	public void sendFirstMsg() {
		getGpcRequest(GpcRequestHandler.createRequest(this));
	}

	public void sendConnectMsg(int time) {
		getGpcRequest(GpcRequestHandler.createRequest(this).setHeader("time", String.valueOf(time)));
	}

	public void ReadAndWriteStart() throws IOException {
		while(true) {
			// 阻塞,等待事件发生,或者1秒超时. num为发生事件的数量.
			int num = selector.select();
			if(num>0) {
				Set<SelectionKey> keys = selector.selectedKeys();
				Iterator<SelectionKey> it = keys.iterator();
				while (it.hasNext()) {
					SelectionKey key = it.next();
					if(key.isValid()){
						if (key.isReadable()) {
							SocketChannel sc = (SocketChannel)key.channel();
							ByteBuffer buffer = ByteBuffer.allocate(1024);
							ByteArrayOutputStream baos = new ByteArrayOutputStream();
							int len = sc.read(buffer);
							// 清空buffer
							if(len==-1) {
								key.channel().close();
								key.cancel();
								return;
							}
							buffer.flip();
							while (buffer.hasRemaining()) {
								baos.write(buffer.get());
							}
							GpcRequest response = StreamUtils.unserialize(baos.toByteArray());
							//GpcResponseReader.getInstance().response(response);
							if("-1".equals(id)) {
								id = response.getHeader(GpcRequestHandler.X_ENTITY_ID);
							}
							baos.close();
						} 
					}
					it.remove();
				}
			}
		}
	}

	public void getGpcRequest(GpcRequest request) {
		//基于客户端构造请求头
		request.setHeader(GpcRequestHandler.X_ENTITY_ID,id);
		request.setHeader(GpcRequestHandler.X_IP,ip);
		request.setHeader(GpcRequestHandler.X_PORT,port);
		//将请求发送至服务端
		sendGpcMessage(request);
	}

	public void sendGpcMessage(GpcRequest request) {
		this.write(StreamUtils.serialize(request));
	}

	private void write(byte[] message) {
		ByteBuffer buffer = ByteBuffer.allocate(1024);
		buffer.put(message);
		buffer.flip();
		try {
			socketChannel.write(buffer);
		} catch (IOException e) {
			e.printStackTrace();
		}
		buffer.clear();
	}

}
